Let’s Build a Chatbot

Using Shiny, OpenAI, and RStudio to Build a Chatbot

James Wade

API Calls

An Example from OpenAI Docs


curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
}'

Constructing Messages for OpenAI


The message body:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"}
  ]
}

Send requests with {httr2}

library(httr2)
library(purrr)

Send requests with {httr2}

library(httr2)
library(purrr)

# construct the message body
user_message <- list(list(role = "user", content = "Hello"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)

Send requests with {httr2}

library(httr2)
library(purrr)

# construct the message body
user_message <- list(list(role = "user", content = "Hello!"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)

# send the request
resp <-
  request("https://api.openai.com/v1") |> 
  req_url_path_append("chat/completions") |> 
  req_auth_bearer_token(token = Sys.getenv("OPENAI_API_KEY")) |> 
  req_body_json(body) |> 
  req_perform()

Send requests with {httr2}

library(httr2)
library(purrr)

# construct the message body
user_message <- list(list(role = "user", content = "Hello!"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)

# send the request
resp <-
  request("https://api.openai.com/v1") |>
  req_url_path_append("chat/completions") |> 
  req_auth_bearer_token(token = Sys.getenv("OPENAI_API_KEY")) |> 
  req_body_json(body) |> 
  req_perform()

# process the response
resp |>
  resp_body_json(simplifyVector = TRUE) |> 
  pluck("choices", "message", "content")
[1] "Hello! How can I assist you today?"

Examining the Response

resp |> 
  resp_body_json(simplifyVector = TRUE)
$id
[1] "chatcmpl-8tGDPOeH6tHHzuoZOVUhZ0LhI1tQq"

$object
[1] "chat.completion"

$created
[1] 1708181063

$model
[1] "gpt-3.5-turbo-0125"

$choices
  index message.role                    message.content logprobs finish_reason
1     0    assistant Hello! How can I assist you today?       NA          stop

$usage
$usage$prompt_tokens
[1] 9

$usage$completion_tokens
[1] 9

$usage$total_tokens
[1] 18


$system_fingerprint
[1] "fp_69829325d0"

Wrapping it in a function

library(httr2)
library(purrr)

chat <- function(message, api_key = Sys.getenv("OPENAI_API_KEY")) {
  user_message <- list(list(role = "user", content = message))
  body <- list(model = "gpt-3.5-turbo",
               messages = user_message)
  resp <-
    request("https://api.openai.com/v1") |> 
    req_url_path_append("chat/completions") |> 
    req_auth_bearer_token(token = api_key) |> 
    req_body_json(body) |> 
    req_perform()
  
  resp |> 
    resp_body_json(simplifyVector = TRUE) |> 
    pluck("choices", "message", "content")
}

Let’s Try it Out

Trying out chat()


chat("What is your favorite color?")
[1] "I'm not able to perceive colors as I am an AI and don't have personal preferences."


chat("Show me a simple ggplot2 example. Only code with comments. Be brief.")
[1] "```R\n# Load the ggplot2 package\nlibrary(ggplot2)\n\n# Create a scatter plot of Sepal Length vs Sepal Width from the iris dataset\nggplot(data = iris, aes(x = Sepal.Length, y = Sepal.Width)) +\n  geom_point()\n```"

A Prettier Response

answer <- chat("Make a ggplot2 in an RMarkdown document and briefly tell me
               what you made.")
answer |> cat()
```{r}
library(ggplot2)

# Create a scatter plot with random data
data <- data.frame(x = rnorm(100), y = rnorm(100))
ggplot(data, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Random Scatter Plot", 
       x = "X Values", y = "Y Values")
```

I created a scatter plot using ggplot2 in an RMarkdown document. The plot uses random data with 100 rows and two columns (x and y). I added a title and labeled the x and y axes.

An Even Prettier Response

library(ggplot2)

# Create a scatter plot with random data
data <- data.frame(x = rnorm(100), y = rnorm(100))
ggplot(data, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Random Scatter Plot", 
       x = "X Values", y = "Y Values")

I created a scatter plot using ggplot2 in an RMarkdown document. The plot uses random data with 100 rows and two columns (x and y). I added a title and labeled the x and y axes.

Helper Functions

chat()

chat <- function(user_message, 
                 history = NULL,
                 system_prompt = c("general", "code"),
                 api_key = Sys.getenv("OPENAI_API_KEY")) {
  system   <- get_system_prompt(system_prompt)
  prompt   <- prepare_prompt(user_message, system_prompt, history)
  base_url <- "https://api.openai.com/v1"
  body     <- list(model = "gpt-3.5-turbo",
                   messages = prompt)
  
  # <httr2_request_pipeline>
  # <process_response>
}

Helper Functions

get_system_prompt()

get_system_prompt <- function(system = c("general", "code")) {
  instructions <- 
    switch(system,
           "general" = "You are a helpful assistant.",
           "code"    = "<code_assistant_prompt>")
  list(list(role = "system", content = instructions))
}


prepare_prompt()

prepare_prompt <- function(user_message, system_prompt, history) {
  user_prompt <-  list(list(role = "user", content = user_message))
  c(system_prompt, history, user_prompt) |> compact()
}

Shiny Build

30:00

Deployment